package gov.nist.applet.phone.media.messaging;

import gov.nist.applet.phone.media.transmitter.StateListener;

import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Image;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.media.Buffer;
import javax.media.ConfigureCompleteEvent;
import javax.media.Control;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.DataSink;
import javax.media.Format;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoDataSinkException;
import javax.media.NotConfiguredError;
import javax.media.Player;
import javax.media.Processor;
import javax.media.RealizeCompleteEvent;
import javax.media.control.FrameGrabbingControl;
import javax.media.control.TrackControl;
import javax.media.format.AudioFormat;
import javax.media.format.VideoFormat;
import javax.media.protocol.DataSource;
import javax.media.protocol.FileTypeDescriptor;
import javax.media.util.BufferToImage;
import javax.swing.JOptionPane;


//import jmapps.util.StateHelper;

public class SaveAudioVideo2File {

	/**
	 * @param args
	 */
	Processor processor = null;
	DataSink dataSink = null;
	StateHelper state = null;
	MediaLocator mediaLocator = null;
	boolean encodingOK = false;
	private static boolean  isStart = false;


	public boolean record(DataSource ds)
	{
//		Format formats[] = new Format[2];
//		formats[0] = new AudioFormat(AudioFormat.IMA4);
//		formats[1] = new VideoFormat(VideoFormat.H263);
		
		
//		FileTypeDescriptor outputType = new FileTypeDescriptor(
//				FileTypeDescriptor.QUICKTIME);
//		try
//		{
//			processor = Manager.createRealizedProcessor(new ProcessorModel(ds,formats,outputType));
//		} catch (Exception e2)
//		{
//			e2.printStackTrace();
//		}
		
		try {
	
			this.processor = Manager.createProcessor(ds);
			
		} catch (Exception e1)
		{
			System.err.println("no such processor exception");
			e1.printStackTrace();
			return false;
		}
		this.state = new StateHelper(processor);
		//this.state = new jmapps.util.StateHelper(processor);
		if(!state.configure(5000))
		{
			System.out.println("configure error :");
			return false;
		}
		// Wait for it to configure
//		StateListener stateListener = new StateListener();
//		boolean result = stateListener.waitForState(processor,
//				Processor.Configured);
//		if (result == false)
//		{
//			System.err.println("configure error !");
//			return false;
//		}
//			
        TrackControl controls[] = processor.getTrackControls();
        int audioType = 0;
        int videoType = 0;
        for(int i=0;i<controls.length;i++)
        {
        	if(controls[i].getFormat() instanceof AudioFormat)
        	{
//        		AudioFormat audioFormat = new AudioFormat(AudioFormat.G723_RTP,8000.0,8,1);
//        		processor.getTrackControls()[i].setFormat(audioFormat);
        		processor.getTrackControls()[i].setEnabled(true);
        		System.out.println("\n\n\t\t set audio format IMA4");
        		audioType = 1;
        	}
        	else if(controls[i].getFormat() instanceof VideoFormat)
        	{
                //VideoFormat vfmt = new VideoFormat(VideoFormat.CINEPAK);
//        		VideoFormat vfmt = new VideoFormat(VideoFormat.H263_RTP);
//                VideoFormat videoFormat = (VideoFormat) (new VideoFormat(null, new Dimension(352, 288),
//        				Format.NOT_SPECIFIED, null, Format.NOT_SPECIFIED))
//        				.intersects(vfmt);
//                (processor.getTrackControls())[i].setFormat(videoFormat);
                (processor.getTrackControls())[i].setEnabled(true);
                System.out.println("\n\n\t\t set video format CINEPAK");
                videoType = 1;
        	}
        }
        

      // 设置存储录像文件的格式为 .QUICKTIME  
//        if(audioType==1&&videoType==1)
//        	processor.setContentDescriptor(new FileTypeDescriptor(FileTypeDescriptor.QUICKTIME));
//        else if(videoType==1)
//        	processor.setContentDescriptor(new FileTypeDescriptor(FileTypeDescriptor.MSVIDEO));  
//        else if(audioType==1)
//        	processor.setContentDescriptor(new FileTypeDescriptor(FileTypeDescriptor.WAVE));
        
  		processor.setContentDescriptor(new FileTypeDescriptor(FileTypeDescriptor.QUICKTIME));
        
    	// realize the processor，让 processor 进入 realized 状态  
//      if (!state.realize(1000)) {  
//          System.out.println("realize error!");  
//          return false; 
//      }  
        	boolean result = state.realize(5000);
//        result = stateListener.waitForState(processor, Processor.Realized);
        if(result==false)
        {
        	System.err.println("realize the processor error!");
        	return false;
        }
        
        Control control = processor.getControl("javax.media.control.FrameRateControl");
        if ( control != null && control instanceof javax.media.control.FrameRateControl )
           ((javax.media.control.FrameRateControl)control).setFrameRate(10.0f);
    
  
	
	
//		boolean encodingOK = false;
//
//		encodingOK = setTracks(processor, encodingOK);
//		if(!encodingOK)
//		{
//			System.err.println("encoding error!");
//			return false;
//		}
		
		try
		{
			this.dataSink = Manager.createDataSink(processor.getDataOutput(), getMediaLocator());
		} catch (NoDataSinkException e1)
		{
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		try
		{
			if(dataSink!=null)
			{	
				dataSink.open();
				dataSink.start();	
				isStart = true;
				System.out.println("recoding is start");
				System.out.println("datasink start");
			}
		
		} catch (SecurityException e)
		{
			e.printStackTrace();
			return false;
		} catch (IOException e)
		{
			e.printStackTrace();
			return false;
		}
		
		processor.start();
		return true;
	}
	
 
    
	private MediaLocator getMediaLocator()
	{

		 Frame saveVideoFrame = new Frame("保存视频文件");  
         FileDialog saveVideoFileDialog = new FileDialog(saveVideoFrame, "保存视频文件", FileDialog.SAVE);  
         saveVideoFileDialog.setFile(".mov");  
         saveVideoFileDialog.setVisible(true);  
         String videoFileSavePath = saveVideoFileDialog.getDirectory();  
         String videoFileSaveName = saveVideoFileDialog.getFile();  
         // 如果输入了保存名字（没有点取消）的话，才可运行  
         if (videoFileSaveName != null) {  
             videoFileSavePath = videoFileSavePath.replace("\\", "/");  
             String destinationString = "file:///" + videoFileSavePath + videoFileSaveName;    
             MediaLocator mediaLocator = new MediaLocator(destinationString);  
             return mediaLocator;
         }
         //if a user not choose a file path,then 
         return new MediaLocator("file://d:/media.mov");
	}
	
	
	public void stopRecord()
	{
	
		if(null==processor)
			return;
			state = null;
			processor.close();
			processor.deallocate();//回收内存
			processor = null;
			isStart = false;
			System.out.println("processor close");		
			
		if(null==dataSink)
			return;
			dataSink.close();//这个代码必须放到processor.deallocate（）后面，要不就会卡死程序
			System.out.println("stop recording,datasink close!");
		

	}
	
	
	/**
	 * save the position you wanted to save this file 
	 * @param ml
	 */
	public void setMediaLocator(MediaLocator ml)
	{
		this.mediaLocator = ml;
	}
	private static boolean setTracks(Processor p, boolean encodingOK)
			throws NotConfiguredError
	{
		TrackControl tracks[] = p.getTrackControls();
		for(int i=0;i<tracks.length;i++)
		{
			if(tracks[i].getFormat() instanceof AudioFormat)
			{
				tracks[i].setFormat(new AudioFormat(AudioFormat.IMA4));
				encodingOK = true;
			}
			else if(tracks[i].getFormat() instanceof VideoFormat)
			{
				tracks[i].setFormat(new VideoFormat(VideoFormat.H263));
				encodingOK = true;
			}
			else
				tracks[i].setEnabled(false);
		}
		return encodingOK;
	}
	
	  public class StateHelper implements ControllerListener {  
	        Player xplayer = null;  
	        boolean configured = false;  
	        boolean realized = false;  
	        // boolean prefetched = false;  
	        // boolean eom = false;// End of media.  
	  
	        boolean failed = false;  
	        boolean closed = false;  
	  
	        public StateHelper(Player p) {  
	            xplayer = p;  
	            p.addControllerListener(this);  
	        }  
	  
	        public boolean configure(int timeOutMillis) {  
	            // RealizeCompleteEvent 发生了的话使 ce 事件与之比较，若相等，那么 realized 为 true。  
	            /* 
	             * 监听 ConfigureCompleteEvent 和 ConfigureCompleteEvent 事件的发生。 
	             * 如 ConfigureCompleteEvent 事件发生，那么就会赋给 configured 为 ture， 使得 public 
	             * boolean configure 方法中的 while (!configured && !failed){} 这个循环退出。 
	             */  
	            long startTime = System.currentTimeMillis();  
	            synchronized (this) {  
	                if (xplayer instanceof Processor) {  
	                    ((Processor) xplayer).configure();  
	                } else {  
	                    return false;  
	                }  
	                while (!configured && !failed) {  
	                    try {  
	                        wait(timeOutMillis);  
	                    } catch (InterruptedException ex) {  
	                        ex.printStackTrace();  
	                    }  
	                    if (System.currentTimeMillis() - startTime > timeOutMillis) {  
	                        break;  
	                    }  
	                }  
	            }  
	            return configured;  
	        }  
	  
	        public boolean realize(int timeOutMillis) {  
	            long startTime = System.currentTimeMillis();  
	            synchronized (this) {  
	                xplayer.realize();  
	                while (!realized && !failed) {  
	                    try {  
	                        wait(timeOutMillis);  
	                    } catch (InterruptedException ie) {  
	                        ie.printStackTrace();  
	                    }  
	                    if (System.currentTimeMillis() - startTime > timeOutMillis) {  
	                        break;  
	                    }  
	                }  
	            }  
	            return realized;  
	        }  
	  
	        public synchronized void controllerUpdate(ControllerEvent ce) {  
	            if (ce instanceof RealizeCompleteEvent) {  
	                realized = true;  
	            } else if (ce instanceof ConfigureCompleteEvent) {  
	                configured = true;  
	            } else {  
	                return;  
	            }  
	            notifyAll();  
	        }  
	    }  
	  
	  public boolean getRecordState()
	  {
		  return isStart;
	  }

}
